オンプレミスのUbuntuをCloudFomation一撃でAWS Systems Managerに登録してみた
最近どうもLinux端末(特にUbuntu)にご縁があるAWS事業本部の梶原@福岡オフィスです。
- 家の中にあるLinux端末って把握してますか?
- ユーザー管理とかどうしてます?
- IP管理とかどうしてます?
- 端末にディスプレイついてます?
- 出先からアクセスしたくないですか?
- このRaspberry Pi 達パスワード分かんないな。
- 東京に出張した際に、家の機械学習PCのトレーニング状況を知りたいな
- Linux端末セットアップしてくんない?リモートから。
- AWSDeepRacer 車両。。。
そんなあなたに、オンプレミスのマシンの状態を把握できる AWS Systems Manager !
アドバンスドオンプレミスインスタンスにすれば、セッションマネージャーを使ってSSH接続できます。 スタンダードでAWS Systems Manager に登録するだけであれば、追加料金はかかりません!
ということで、とりあえず登録はしておこうかな。
となるんですが、手順や、IAMRole作成などちょっぴり手間ですよね。わかります。
アクティベーションコードはまとめて発行もできるんですが、忘れるんですよね。
ロールも個別作成は結構面倒くさいです。でも基本別々にしたいです。
やりたいことは
- アクティベーションコードを発行する
- アクティベーションする(AWS Systems Manager に登録する)
なんよ。
ということで、CloudFormation一撃化したので、共有します。
やってみた
前提条件
- AWS Systems Managerに登録する端末はインターネット接続が必要です
- もしくは別のネットワーク経路(VPNなど)でAWS Systems Managerのエンドポイントに接続できる必要があります
- AWS Systems ManagerがサポートしているOSである必要があります
- Amazon Linux 2, Amazon Linux, RHEL, Oracle Linux, CentOS, and SLES
- Ubuntu Server
- Debian Server
- Raspberry Pi OS (formerly Raspbian)
- Windows Server
- 上記OSでもバージョン、ハードウェアによってはサポートされていないことがありますので詳しくはサポートされているOSを確認してください
アクティベーションコードを発行する
CloudFormation スタックの作成
CloudFormation のテンプレートを作成しているので下記リンクをクリックして、CloudFormationスタックを作成してください
項目 | 内容 | 備考 |
---|---|---|
スタックの名前 | cfn-ssm-activation | スタックの名称を入力します。 |
MyHybridInstanceName | my-hybrid-instance | SSMに登録する際の名称を入力します |
MyHybridInstanceRoleName | my-hybrid-instance-role | ハイブリッドインスタンスに割り当てるRole名を入力します |
SsmActivationDescription | My Hybrid Instanse Description | アクティベーションのメモです、登録対象のわかりやすい記述を入力してください |
AWS CloudFormation によって IAM リソースがカスタム名で作成される場合があることを承認します。
にチェックを入れて作成します
CloudFormationスタックが正常に作成され以下のリソースが作成されれば成功です。
また、出力に作成したアクティベーションコードが記載されていますので、メモしてください
こちらのアクティベーションコードの有効期間は発行から1日となります。また、アクティベーションの有効数も1つとしていますのですみやかにご使用ください
変更したい方はコードのcreate_activation のパラメータを変更すればカスタム可能です
セキュリティ上保持させたくない場合もあるかと思いますのでその場合は、発行処理から直接Systems Mangaerのパラメータ等に直接保存する処理などもご検討ください
作成されるリソースについて
以下のリソースが作成されます
項目 | 内容 | 備考 |
---|---|---|
LambdaIAMRole | AWS::IAM::Role | カスタムリソースで必要となるRole |
MyHybridInstanceRole | AWS::IAM::Role | ハイブリッドインスタンスに割り当てるRole |
SsmActivation | Custom::SsmActivation | Lambda-backledカスタムリソース(アクティベーションの登録処理を行います) |
SsmActivationLambdaFunction | AWS::Lambda::Function | アクティベーションの登録処理を行うLambda |
ハイブリッドインスタンスに割り当てるRole(MyHybridInstanceRole)について
以下の権限を割り当てています。
- AmazonSSMManagedInstanceCore
- CloudWatchAgentServerPolicy
- CloudWatchLogsにログ等を出力する際に必要
- KmsDecrypt (全キーのDecrypt権限)
- セッションマネージャーで接続する際にkms暗号化を使用する場合に必要
参考
また、AWS Systems Manager のアクティベーションのコンソールを確認すると作成されていると思いますので、ご確認ください。
AWS Systems Manager >アクティベーション
https://ap-northeast-1.console.aws.amazon.com/systems-manager/activations?region=ap-northeast-1
アクティベーションする
正確にはハイブリッド環境 (Linux) に SSM Agent をインストール する作業になります
他のOS等、最新の手順は以下公式ドキュメントを参考にしてください
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/sysman-install-managed-linux.html
Ubuntu を実行しているマシンにログインします
先程メモした、アクティベーションID,アクティベーションコードを使用します
以下コマンドの activation-code, activation-id を 置き換えてください
また、リージョンはCloudFromationスタックを作成したリージョンとなります (東京の場合はap-northeast-1)
sudo snap install amazon-ssm-agent --classic sudo systemctl stop snap.amazon-ssm-agent.amazon-ssm-agent.service sudo /snap/amazon-ssm-agent/current/amazon-ssm-agent -register -code "activation-code" -id "activation-id" -region "region" sudo systemctl start snap.amazon-ssm-agent.amazon-ssm-agent.service
正常に登録されると登録済インスタンスが0から1になります。
AWS Systems Manager >アクティベーション
https://ap-northeast-1.console.aws.amazon.com/systems-manager/activations?region=ap-northeast-1
AWS Systems Manager で管理する
正常に登録されていれば
AWS Systems Manager > フリートマネージャー
の方にも表示されるかと思います。
スクロールすると状況やSSM Agentのバージョンなどもあります
また、ノードIDをクリックし対象のインスタンスの詳細が確認できるかとおもいます。
ノードの概要
また、スタンダードでは表示できませんが、高度なインスタンス枠に変更すると、パフォーマンスカウンターなども表示することができます
- ファイル転送
- プロセス作成(高度なインスタンス)
- ユーザー、グループ作成
も行えますので、Systems Mangerを使用して管理してみてください。
作成したCloudFormationのスタックを消す(オプション)
今回使用したスタックでは、アクティベーションまた、ハイブリッドインスタンスが使用しているRoleは
DeletionPolicy: Retain
で定義していますので、CloudFormationスタックを消しても残ります。
カスタムリソースなどはアクティベーション後には不要になりますので、消していただいて問題ありません。
逆に、アクティベーションまた、ハイブリッドインスタンスは残るので手作業で消して頂く必要があります。 まとめて消したい場合は、DeletionPolicyの設定を削除するか変更してください
料金について
スタンダードであれば、現在(2022/06/12) 1000台/リージョンごと まで追加料金なしで登録できます!
インスタンスに対して、SSH接続、ポートフォワード等をする場合にアドバンスドインスタンスを有効化する必要があります。スタンダードとアドバンスドの切り替え の実施はアドバンスドからスタンダードに変更する際に時間がかかりますので、(1時間以下)、ポチポチすることはできませんが、アドバンスドに変更する操作はすぐに行えますので、通常はスタンダード、インスタンスに接続したいというときにアドバンスドに変更する運用の方がリーズナブルかと思います。
https://aws.amazon.com/jp/systems-manager/pricing/#On-Premises_Instance_Management
オンプレミスインスタンスティア(アカウントレベルおよびリージョンレベルの設定) | 料金 |
---|---|
スタンダード | 追加料金なし アカウントごとにリージョンあたり最大 1,000 までの制限 |
アドバンスド | アドバンスドオンプレミスインスタンスごとに時間あたり 0.00695 USD 無料利用枠なし |
まとめ
管理対象のインスタンスにログインすることができれば、登録まで5分程度で行けます!
IoTなどで初期化スクリプトなどで組み込めばもっと早いかもしれません。
ロールや、記述などインスタンス毎に別々にしたかったのでサクッといけるようにしてみました。
若干、アクティベーションコードの発行と、アクティベーションの2ステップだと1撃じゃないなと言う気もしなくもないですがご容赦ください。
アカウント迷子のraspiなどが1匹でも少なくなると嬉しいです。
参考情報
ハイブリッド環境で AWS Systems Manager を設定する
CreateActivation API
テンプレート
AWSTemplateFormatVersion: 2010-09-09 Parameters: SsmActivationDescription: Type: String Default: 'My Hybrid Instanse Description' MyHybridInstanceName: Type: String Default: my-hybrid-instance MyHybridInstanceRoleName: Type: String Default: my-hybrid-instance-role Resources: MyHybridInstanceRole: Type: AWS::IAM::Role DeletionPolicy: Retain Properties: Description: Provides permissions for on-premises machines RoleName: !Ref MyHybridInstanceRoleName AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Sid: '' Effect: Allow Principal: Service: ssm.amazonaws.com Action: sts:AssumeRole Condition: StringEquals: aws:SourceAccount: !Ref 'AWS::AccountId' ArnEquals: aws:SourceArn: !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:*' ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy Policies: - PolicyName: KmsDecrypt PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - kms:Decrypt Resource: !Sub 'arn:aws:kms:*:${AWS::AccountId}:key/*' SsmActivation: Type: 'Custom::SsmActivation' DeletionPolicy: Retain Properties: ServiceToken: !GetAtt SsmActivationLambdaFunction.Arn Id: !Sub - SsmActivation-${UniqueId} - UniqueId: !Select [0, !Split ['-', !Select [2, !Split [/, !Ref 'AWS::StackId']]]] Description: !Ref SsmActivationDescription InstanceName: !Ref MyHybridInstanceName IamRole: !Ref MyHybridInstanceRole LambdaArn: !GetAtt SsmActivationLambdaFunction.Arn LambdaIAMRole: Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - 'sts:AssumeRole' Path: / Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 'iam:PassRole' - 'ssm:CreateActivation' - 'ssm:DeleteActivation' Resource: '*' - Effect: Allow Action: - 'logs:CreateLogGroup' - 'logs:CreateLogStream' - 'logs:PutLogEvents' Resource: 'arn:aws:logs:*:*:*' SsmActivationLambdaFunction: Type: 'AWS::Lambda::Function' Properties: Handler: index.lambda_handler Role: !GetAtt LambdaIAMRole.Arn Code: ZipFile: | import json import boto3 import cfnresponse SUCCESS = "SUCCESS" FAILED = "FAILED" print('Loading function') ssm = boto3.client('ssm') def lambda_handler(event, context): print("Received event: " + json.dumps(event, indent=2)) responseData = {} physicalResourceId = None try: print("Request Type:",event['RequestType']) if event['RequestType'] == 'Delete': activation_id = event['PhysicalResourceId'] delete_activation(activation_id) print("Sending response to custom resource after Delete") elif event['RequestType'] == 'Create': description = event['ResourceProperties']['Description'] instance_name = event['ResourceProperties']['InstanceName'] iam_role = event['ResourceProperties']['IamRole'] responseData = create_activation(description, instance_name, iam_role) physicalResourceId = responseData['ActivationId'] print("Sending response to custom resource") responseStatus = 'SUCCESS' except Exception as e: print('Failed to process:', e) responseStatus = 'FAILED' responseData = {'Failure': 'Something bad happened.'} cfnresponse.send(event, context, responseStatus, responseData, physicalResourceId, True) def create_activation(description, instance_name, iam_role): response = ssm.create_activation( Description = description, DefaultInstanceName = instance_name, IamRole = iam_role ) ## print(response) print("Create request completed....") return response def delete_activation(activation_id): ssm.delete_activation( ActivationId = activation_id ) print("Delete request completed....") Runtime: python3.9 Timeout: 60 Outputs: ActivationId: Value: !GetAtt 'SsmActivation.ActivationId' ActivationCode: Value: !GetAtt 'SsmActivation.ActivationCode'